﻿using System.Drawing;
using System.IO;
using GIMS.Def;
using GIMS.Def.Arguments;
using GIMS.Def.Flags;
using GIMS.Def.Settings;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using GIMS.GUI.GraphItems;
using GIMS.GUI;
using System;

namespace GIMS.GUI.Test
{
    /// <summary>
    ///This is a test class for MainWindowViewModelTest and is intended
    ///to contain all MainWindowViewModelTest Unit Tests
    ///</summary>
    [TestClass()]
    public class MainWindowViewModelTest
    {
        private static string tempImagePath;
        private static string tempPath; //"path of the system's temporary folder"+/GIMSTest

        /// <summary>
        /// Reset GlobalSettings
        /// </summary>
        [TestInitialize()]
        public void MyTestInitialize()
        {
            GlobalSettings_Accessor.instance = null;
        }

        [ClassInitialize()]
        public static void Initialize(TestContext testContext)
        {
            tempPath = Path.Combine(Path.GetTempPath(), "GIMSTest");
            if (!Directory.Exists(tempPath))
            {
                Directory.CreateDirectory(tempPath);
            }

            tempImagePath = Path.Combine(tempPath, "amplifier.jpg");
            if (!File.Exists(tempImagePath))
            {
                Resource.amplifier.Save(tempImagePath);
            }
        }

        [ClassCleanup]
        public static void CleanUp()
        {
            if (Directory.Exists(tempPath))
            {
                Directory.Delete(tempPath, true);
            }
        }

        #region UnitTests

        /// <summary>
        ///A test for IncrementEdgeSequence. Increment from 1 to 2 is possible.
        ///</summary>
        [TestMethod()]
        public void IncrementEdgeSequenceTestIncrementPossible1()
        {
            MainWindowViewModel_Accessor target = CreateThreeEdgeGraphMainWindowViewModel();
            var edge1 = target.Graph.Edges.First(p => p.Sequence == 1);
            var edge2 = target.Graph.Edges.First(p => p.Sequence == 2);
            var edge3 = target.Graph.Edges.First(p => p.Sequence == 3);

            target.IncrementEdgeSequence(edge1);
            Assert.AreEqual(2, edge1.Sequence);
            Assert.AreEqual(1, edge2.Sequence);
            Assert.AreEqual(3, edge3.Sequence);
        }

        /// <summary>
        ///A test for IncrementEdgeSequence. Increment from 2 to 3 is possible.
        ///</summary>
        [TestMethod()]
        public void IncrementEdgeSequenceTestIncrementPossible2()
        {
            MainWindowViewModel_Accessor target = CreateThreeEdgeGraphMainWindowViewModel();
            var edge1 = target.Graph.Edges.First(p => p.Sequence == 1);
            var edge2 = target.Graph.Edges.First(p => p.Sequence == 2);
            var edge3 = target.Graph.Edges.First(p => p.Sequence == 3);

            target.IncrementEdgeSequence(edge2);
            Assert.AreEqual(1, edge1.Sequence);
            Assert.AreEqual(3, edge2.Sequence);
            Assert.AreEqual(2, edge3.Sequence);
        }

        /// <summary>
        ///A test for IncrementEdgeSequence. Increment from 3 is not possible.
        ///</summary>
        [TestMethod()]
        public void IncrementEdgeSequenceTestIncrementNotPossible()
        {
            MainWindowViewModel_Accessor target = CreateThreeEdgeGraphMainWindowViewModel();
            var edge1 = target.Graph.Edges.First(p => p.Sequence == 1);
            var edge2 = target.Graph.Edges.First(p => p.Sequence == 2);
            var edge3 = target.Graph.Edges.First(p => p.Sequence == 3);

            target.IncrementEdgeSequence(edge3);
            Assert.AreEqual(1, edge1.Sequence);
            Assert.AreEqual(2, edge2.Sequence);
            Assert.AreEqual(3, edge3.Sequence);
        }

        /// <summary>
        ///A test for DecrementEdgeSequence. Decrement from 2 to 1 is possible.
        ///</summary>
        [TestMethod()]
        public void DecrementEdgeSequenceTestDecrementPossible1()
        {
            MainWindowViewModel_Accessor target = CreateThreeEdgeGraphMainWindowViewModel();
            var edge1 = target.Graph.Edges.First(p => p.Sequence == 1);
            var edge2 = target.Graph.Edges.First(p => p.Sequence == 2);
            var edge3 = target.Graph.Edges.First(p => p.Sequence == 3);

            target.DecrementEdgeSequence(edge2);
            Assert.AreEqual(2, edge1.Sequence);
            Assert.AreEqual(1, edge2.Sequence);
            Assert.AreEqual(3, edge3.Sequence);
        }

        /// <summary>
        ///A test for DecrementEdgeSequence. Decrement from 3 to 2 is possible.
        ///</summary>
        [TestMethod()]
        public void DecrementEdgeSequenceTestDecrementPossible2()
        {
            MainWindowViewModel_Accessor target = CreateThreeEdgeGraphMainWindowViewModel();
            var edge1 = target.Graph.Edges.First(p => p.Sequence == 1);
            var edge2 = target.Graph.Edges.First(p => p.Sequence == 2);
            var edge3 = target.Graph.Edges.First(p => p.Sequence == 3);

            target.DecrementEdgeSequence(edge3);
            Assert.AreEqual(1, edge1.Sequence);
            Assert.AreEqual(3, edge2.Sequence);
            Assert.AreEqual(2, edge3.Sequence);
        }

        /// <summary>
        ///A test for DecrementEdgeSequence. 
        ///</summary>
        [TestMethod()]
        public void DecrementEdgeSequenceTestDecrementNotPossible()
        {
            MainWindowViewModel_Accessor target = CreateThreeEdgeGraphMainWindowViewModel();
            var edge1 = target.Graph.Edges.First(p => p.Sequence == 1);
            var edge2 = target.Graph.Edges.First(p => p.Sequence == 2);
            var edge3 = target.Graph.Edges.First(p => p.Sequence == 3);

            target.DecrementEdgeSequence(edge1);
            Assert.AreEqual(1, edge1.Sequence);
            Assert.AreEqual(2, edge2.Sequence);
            Assert.AreEqual(3, edge3.Sequence);
        }

        /// <summary>
        ///A test for the correct edge sequence.
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GIMS.GUI.exe")]
        public void Graph_EdgeSequenceTest_OneNewEdge()
        {
            MainWindowViewModel_Accessor target = CreateEmptyGraphMainWindowViewModel();
            var loadVertex1 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var saveVertex = new CustomVertex(OperatorFactory.GetOperator("save"));
            target.Graph.AddVertexRange(new CustomVertex[] { loadVertex1, saveVertex });

            target.Graph.AddNewEdgeBetween(loadVertex1, saveVertex);
            Assert.AreEqual(1, target.Graph.Edges.Count(p => p.Sequence == 1));
        }

        /// <summary>
        ///A test for the correct edge sequence.
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GIMS.GUI.exe")]
        public void Graph_EdgeSequenceTest_ThreeNewEdges()
        {
            MainWindowViewModel_Accessor target = CreateEmptyGraphMainWindowViewModel();
            var loadVertex1 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var loadVertex2 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var loadVertex3 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var saveVertex = new CustomVertex(OperatorFactory.GetOperator("save"));
            target.Graph.AddVertexRange(new CustomVertex[] { loadVertex1, loadVertex2, loadVertex3, saveVertex });

            target.Graph.AddNewEdgeBetween(loadVertex1, saveVertex);
            target.Graph.AddNewEdgeBetween(loadVertex2, saveVertex);
            target.Graph.AddNewEdgeBetween(loadVertex3, saveVertex);

            Assert.AreEqual(1, target.Graph.Edges.Count(p => p.Sequence == 1));
            Assert.AreEqual(1, target.Graph.Edges.Count(p => p.Sequence == 2));
            Assert.AreEqual(1, target.Graph.Edges.Count(p => p.Sequence == 3));
        }

        /// <summary>
        ///A test for the correct edge sequence.
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GIMS.GUI.exe")]
        public void Graph_EdgeSequenceTest_DeletedVertex1()
        {
            MainWindowViewModel_Accessor target = CreateEmptyGraphMainWindowViewModel();
            var loadVertex1 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var loadVertex2 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var loadVertex3 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var saveVertex = new CustomVertex(OperatorFactory.GetOperator("save"));

            target.Graph.AddNewVertex(saveVertex);
            target.Graph.AddNewSourceToVertex(saveVertex, loadVertex1);
            target.Graph.AddNewSourceToVertex(saveVertex, loadVertex2);
            target.Graph.AddNewSourceToVertex(saveVertex, loadVertex3);
            

            target.Graph.DeleteVertex(loadVertex1);
            Assert.AreEqual(1, target.Graph.Edges.Count(p => p.Sequence == 1));
            Assert.AreEqual(1, target.Graph.Edges.Count(p => p.Sequence == 2));
        }

        /// <summary>
        ///A test for the correct edge sequence.
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GIMS.GUI.exe")]
        public void Graph_EdgeSequenceTest_DeletedVertex2()
        {
            MainWindowViewModel_Accessor target = CreateEmptyGraphMainWindowViewModel();
            var loadVertex1 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var loadVertex2 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var loadVertex3 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var saveVertex = new CustomVertex(OperatorFactory.GetOperator("save"));

            target.Graph.AddNewVertex(saveVertex);
            target.Graph.AddNewSourceToVertex(saveVertex, loadVertex1);
            target.Graph.AddNewSourceToVertex(saveVertex, loadVertex2);
            target.Graph.AddNewSourceToVertex(saveVertex, loadVertex3);


            target.Graph.DeleteVertex(loadVertex2);
            Assert.AreEqual(1, target.Graph.Edges.Count(p => p.Sequence == 1));
            Assert.AreEqual(1, target.Graph.Edges.Count(p => p.Sequence == 2));
        }

        /// <summary>
        ///A test for the correct edge sequence.
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GIMS.GUI.exe")]
        public void Graph_EdgeSequenceTest_DeletedVertex3()
        {
            MainWindowViewModel_Accessor target = CreateEmptyGraphMainWindowViewModel();
            var loadVertex1 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var loadVertex2 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var loadVertex3 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var saveVertex = new CustomVertex(OperatorFactory.GetOperator("save"));

            target.Graph.AddNewVertex(saveVertex);
            target.Graph.AddNewSourceToVertex(saveVertex, loadVertex1);
            target.Graph.AddNewSourceToVertex(saveVertex, loadVertex2);
            target.Graph.AddNewSourceToVertex(saveVertex, loadVertex3);

            target.Graph.DeleteVertex(loadVertex3);
            Assert.AreEqual(1, target.Graph.Edges.Count(p => p.Sequence == 1));
            Assert.AreEqual(1, target.Graph.Edges.Count(p => p.Sequence == 2));
        }

        /// <summary>
        ///A test HasSequence on CustomEdge-Class.
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GIMS.GUI.exe")]
        public void HasSequenceTest1()
        {
            var viewModel = CreateTwoVerticesGraphMainWindowViewModel();
            var edge = viewModel.Graph.Edges.Single();
            Assert.IsFalse(edge.HasSequence);
        }

        /// <summary>
        ///A test HasSequence on CustomEdge-Class.
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GIMS.GUI.exe")]
        public void HasSequenceTest2()
        {
            MainWindowViewModel_Accessor target = CreateEmptyGraphMainWindowViewModel();
            var loadVertex1 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var loadVertex2 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var loadVertex3 = new CustomVertex(OperatorFactory.GetOperator("load"));
            var saveVertex = new CustomVertex(OperatorFactory.GetOperator("save"));
            target.Graph.AddVertexRange(new CustomVertex[] { loadVertex1, loadVertex2, loadVertex3, saveVertex });

            target.Graph.AddNewEdgeBetween(loadVertex1, saveVertex);
            target.Graph.AddNewEdgeBetween(loadVertex2, saveVertex);
            target.Graph.AddNewEdgeBetween(loadVertex3, saveVertex);

            foreach (var edge in target.Graph.Edges)
            {
                Assert.IsTrue(edge.HasSequence);
            }

            target.Graph.DeleteVertex(loadVertex1);
            target.Graph.DeleteVertex(loadVertex2);
            Assert.IsFalse(target.Graph.Edges.Single().HasSequence);
        }

        #endregion

        #region Helper Methods

        private MainWindowViewModel_Accessor CreateEmptyGraphMainWindowViewModel()
        {
            var vm = new MainWindowViewModel_Accessor();
            return vm;
        }

        private MainWindowViewModel_Accessor CreateTwoVerticesGraphMainWindowViewModel()
        {
            var vm = new MainWindowViewModel_Accessor();
            var loadVertex = new CustomVertex(OperatorFactory.GetOperator("Load"));
            var saveVertex = new CustomVertex(OperatorFactory.GetOperator("Save"));

            vm.Graph.AddNewVertex(loadVertex);
            vm.Graph.AddNewVertexToSource(loadVertex, saveVertex);
            return vm;
        }

        private MainWindowViewModel_Accessor CreateThreeEdgeGraphMainWindowViewModel()
        {
            var vm = CreateTwoVerticesGraphMainWindowViewModel();
            var loadVertex2 = new CustomVertex(OperatorFactory.GetOperator("Load"));
            var loadVertex3 = new CustomVertex(OperatorFactory.GetOperator("Load"));
            var saveVertex = vm.Graph.Vertices.First(p => p.Name == "Save");
            vm.Graph.AddNewSourceToVertex(saveVertex, loadVertex2);
            vm.Graph.AddNewSourceToVertex(saveVertex, loadVertex3);
            return vm;
        }

        /// <summary>
        ///A test for IsScriptExecutable. IsScriptExecutable returns false if Graph is empty.
        ///</summary>
        [TestMethod()]
        public void IsScriptExecutableTest1()
        {
            MainWindowViewModel target = new MainWindowViewModel(); 
            bool expected = false; // 
            bool actual;
            actual = target.IsScriptExecutable();
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for IsScriptExecutable. IsScriptExecutable returns false if there is no save and the current program is convert
        ///</summary>
        [TestMethod()]
        public void IsScriptExecutableTest2()
        {
            var target = new MainWindowViewModel();
            target.CurrentProgram = Program.convert;
            var loadVertex = new CustomVertex(OperatorFactory.GetOperator("Load"));
            target.Graph.AddNewVertex(loadVertex);
            bool expected = false; // 
            bool actual;
            actual = target.IsScriptExecutable();
            Assert.AreEqual(expected, actual);
        }

        #endregion Helper Methods

        #region Integration Tests
        /// <summary>
        ///Integration test NR.1
        ///Load 2 images, append them and check the size of the resulting image
        ///</summary>
        [TestMethod()]
        [DeploymentItem("GIMS.GUI.exe")]
        public void Integration1()
        {
            var target = new MainWindowViewModel_Accessor();
            target.currentProgram = Program.convert;
            var graph = target.Graph;

            var load1 = new CustomVertex(OperatorFactory.GetOperator("Load"));
            var load2 = new CustomVertex(OperatorFactory.GetOperator("Load"));
            var append = new CustomVertex(OperatorFactory.GetOperator("Append"));
            var save = new CustomVertex(OperatorFactory.GetOperator("Save"));

            graph.AddNewVertex(load1);
            graph.AddNewVertex(load2);
            graph.AddNewVertex(append);
            graph.AddNewVertex(save);

            graph.AddNewEdgeBetween(load1, append);
            graph.AddNewEdgeBetween(load2, append);
            graph.AddNewEdgeBetween(append, save);

            PathArgument pa1 = (PathArgument)load1.IMOperator.Argument;
            pa1.Path = tempImagePath;
            PathArgument pa2 = (PathArgument)load2.IMOperator.Argument;
            pa2.Path = tempImagePath;

            Image img = Image.FromFile(append.PreviewImagePath);

            Assert.AreEqual(1536, img.Height);
            Assert.AreEqual(1024, img.Width);
        }

        #endregion Integration Tests




    }
}
